﻿using System.Security.Cryptography;

namespace Signit.Sdk.Util
{
    public static class AesTool
    {
        /// <summary>
        /// 获取所使用 AES 算法的块大小，单位：位
        /// </summary>
        public static int BlockSize { get { return Aes.BlockSize; } }

        /// <summary>
        /// 获取所使用 AES 算法的 Key 大小，单位：位
        /// </summary>
        public static int KeySize { get { return Aes.KeySize; } }

        /// <summary>
        /// 直接通过密码对数据加密。加密所使用的初始化向量根据密码生成。
        /// </summary>
        /// <param name="me">需要加密的数据</param>
        /// <param name="password">密码，不能为 <c>null</c>，但可以是 <c>string.Empty</c></param>
        /// <returns>加密后的数据</returns>
        public static byte[] AesEncrypt(this byte[] me, string password)
        {
            return SymmetricTool.Encrypt(Aes, password, me);
        }

        /// <summary>
        /// 直接通过密码对数据加密。加密所使用的初始化向量根据密码生成。
        /// </summary>
        /// <param name="me">需要加密的数据，不能为 <c>null</c></param>
        /// <param name="start">起始位置</param>
        /// <param name="length">需要加密的数据长度</param>
        /// <param name="password">密码，不能为 <c>null</c>，但可以是 <c>string.Empty</c></param>
        /// <returns>加密后的数据</returns>
        public static byte[] AesEncrypt(this byte[] me, int start, int length, string password)
        {
            return SymmetricTool.Encrypt(Aes, password, me, start, length);
        }

        /// <summary>
        /// 直接通过密码对数据解密。解密所使用的初始化向量根据密码生成。
        /// </summary>
        /// <param name="me">需要解密的数据</param>
        /// <param name="password">密码，不能为 <c>null</c>，但可以是 <c>string.Empty</c></param>
        /// <returns>解密后的数据</returns>
        public static byte[] AesDecrypt(this byte[] me, string password)
        {
            return SymmetricTool.Decrypt(Aes, password, me);
        }

        /// <summary>
        /// 使用AES加密数据。
        /// </summary>
        /// <param name="me">数据字节</param>
        /// <param name="iv">初始化向量</param>
        /// <param name="key">密钥</param>
        /// <returns>加密后的数据。
        /// 如果原数据是<c>null</c>，则返回<c>null</c></returns>
        /// <remarks>如果需要加密字符串，可以使用<c>string.ToByteArray</c>扩展方法
        /// 先把string转换成字符数组</remarks>
        public static byte[] AesEncrypt(this byte[] me, byte[] iv, byte[] key)
        {
            return InternalTool.Encrypt(Aes, me, iv, key);
        }

        /// <summary>
        /// 使用AES加密数据
        /// </summary>
        /// <param name="me">数据字节</param>
        /// <param name="iv">随机产生初始化向量并通过<c>iv</c>返回。
        /// 如果源数据是<c>null</c>，返回<c>null</c></param>
        /// <param name="key">密钥</param>
        /// <returns>加密后的数据。如果原数据是<c>null</c>，则返回<c>null</c></returns>
        /// <remarks>如果需要加密字符串，可以使用<c>string.ToByteArray</c>扩展方法
        /// 先把string转换成字符数组</remarks>
        public static byte[] AesEncrypt(this byte[] me, out byte[] iv, byte[] key)
        {
            return InternalTool.Encrypt(Aes, me, out iv, key);
        }

        /// <summary>
        /// 使用AES解密（加密后的）数据
        /// </summary>
        /// <param name="me">数据字节</param>
        /// <param name="iv">初始化向量</param>
        /// <param name="key">密钥</param>
        /// <returns>解密后的数据，即源数据。
        /// 如果数据字节是<c>null</c>，返回<c>null</c></returns>
        public static byte[] AesDecrypt(this byte[] me, byte[] iv, byte[] key)
        {
            return InternalTool.Decrypt(Aes, me, iv, key);
        }

        private static Aes Aes { get { return aesInstance ?? (aesInstance = Aes.Create()); } }
        private static Aes aesInstance;
    }
}
